﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework;

namespace FrogEngine
{
	public class StatefulParticleEffect : GameEntityBase, IHasContent
	{
		public StatefulParticleEffect(IEngine engine)
			: base(engine)
		{
			Services.Add(engine.GetService<GameContentService>());

			foreach (var service in Services)
				service.Subscribe(this);
		}

		private Effect actualEffect;

		private ContentManager contentManager;
		public ContentManager ContentManager
		{
			get { return contentManager; }
			set { contentManager = value; }
		}

		public IEnumerable<string> AssetNames()
		{
			return new List<string> { "StatefulParticleShader" };
		}

		public void LoadContent()
		{
			this.actualEffect = this.ContentManager.Load<Effect>("StatefulParticleShader");
		}

		public Effect ActualEffect { get { return this.actualEffect; } }
		public EffectTechnique CurrentTechnique { get { return this.actualEffect.CurrentTechnique; } }

		public void StartVelocityTechnique()
		{
			this.actualEffect.CurrentTechnique = this.actualEffect.Techniques.Single(t => t.Name == "Velocity");
		}

		public void StartPositionTechnique()
		{
			this.actualEffect.CurrentTechnique = this.actualEffect.Techniques.Single(t => t.Name == "Position");
		}

		public void StartRenderTechnique()
		{
			this.actualEffect.CurrentTechnique = this.actualEffect.Techniques.Single(t => t.Name == "Render");
		}

		public void SetShaderParameters(StatefulParticleShaderState state)
		{
			this.actualEffect.Parameters["World"].SetValue(state.World);
			this.actualEffect.Parameters["View"].SetValue(state.View);
			this.actualEffect.Parameters["Projection"].SetValue(state.Projection);
			this.actualEffect.Parameters["ViewPortScale"].SetValue(state.ViewPortScale);
			this.actualEffect.Parameters["size"].SetValue(state.size);
			this.actualEffect.Parameters["dt"].SetValue(state.dt);
			this.actualEffect.Parameters["globalForce"].SetValue(state.globalForce);
			this.actualEffect.Parameters["attractiveLocalCount"].SetValue(state.attractiveLocalCount);
			this.actualEffect.Parameters["attractiveLocals"].SetValue(state.attractiveLocals);
			this.actualEffect.Parameters["attractiveLocalMagnitudes"].SetValue(state.attractiveLocalMagnitudes);
			this.actualEffect.Parameters["repulsiveLocalCount"].SetValue(state.repulsiveLocalCount);
			this.actualEffect.Parameters["repulsiveLocals"].SetValue(state.repulsiveLocals);
			this.actualEffect.Parameters["repulsiveLocalMagnitudes"].SetValue(state.repulsiveLocalMagnitudes);
			this.actualEffect.Parameters["ParticleTex"].SetValue(state.ParticleTex);
			this.actualEffect.Parameters["PositionTex"].SetValue(state.PositionTex);
			this.actualEffect.Parameters["VelocityTex"].SetValue(state.VelocityTex);
		}
	}

	public class StatefulParticleShaderState
	{
		public Matrix World { get; set; }
		public Matrix View { get; set; }
		public Matrix Projection { get; set; }
		public Vector2 ViewPortScale { get; set; }
		public float size { get; set; }
		public float dt { get; set; }
		public Vector3 globalForce { get; set; }
		public float attractiveLocalCount { get; set; }
		public Vector3[] attractiveLocals { get; set; }
		public float[] attractiveLocalMagnitudes { get; set; }
		public float repulsiveLocalCount { get; set; }
		public Vector3[] repulsiveLocals { get; set; }
		public float[] repulsiveLocalMagnitudes { get; set; }

		public Texture2D ParticleTex { get; set; }
		public Texture2D PositionTex { get; set; }
		public Texture2D VelocityTex { get; set; }
	}
}
